﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Health;

namespace SPHealth.SharePoint.HealthRules.SP.Rules.Security
{
    class WarnExcessiveUniquelySecuredItems: SPHealthAnalysisRule
    {
        
        #region Locals
        private const string MaxUniquePermissions = "MaxUniquePermissions";
        private const string ruleTitle = "WarnExcessiveUniquelySecuredItems";
        private const string GET_UNIQUE_PERMS_COUNT = @"SELECT count(*) as counter FROM TVF_Perms_Site('{0}')";
        private string results = "";
        private SPHealthAnalysisRuleAutomaticExecutionParameters _executionParameters;
        #endregion

        #region Constructor
        /* This rules does not require a constructor */
        #endregion
        
        #region Fields

        public override string Summary
        {
            get { return "One or more Site Collections have an excessive amount of uniquely permissioned items."; }
        }
        
        public override string Explanation
        {
            get 
            { 
                return String.Format("The following Site Collections have more than {0} uniquely permissioned items:\r\n\r\n{1}", common.GetRuleSetting(MaxUniquePermissions, ruleTitle), results); 
            }
        }

        public override string Remedy
        {
            get { return "Large numbers of uniquely secured items can impact performance and caching."; } // TODO - add some reference articles
        }

        public override SPHealthCheckErrorLevel ErrorLevel
        {
            get { return SPHealthCheckErrorLevel.Warning; }
        }

        public override SPHealthCategory Category
        {
            get { return SPHealthCategory.Security; }
        }
                
        public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
        {
            get
            {
                if (_executionParameters == null)
                {
                    _executionParameters = new SPHealthAnalysisRuleAutomaticExecutionParameters
                    {
                        Schedule = SPHealthCheckSchedule.Daily,
                        Scope = SPHealthCheckScope.Any,
                        ServiceType = typeof(SPTimerService), //Tell SP if we want our own timer job or can we run with others...
                        RepairAutomatically = false
                    };
                }
                return _executionParameters;
            }
        }
        
        #endregion

        #region Methods

        // used to provide the configuration list item title
        public static string GetTitle()
        {
            // return the title for the rule
            return ruleTitle;
        }

        // used to provide the default configuration settings
        public static IDictionary<string,string> GetDefaultSettings()
        {
            // return the default settings for the rule
            IDictionary<string,string> settings = new Dictionary<string,string>();
            settings.Add("Comment1", "Enter the maximum number of uniquely permissioned");
            settings.Add("Comment2", "items that can exist before a warning is raised.");
            settings.Add(MaxUniquePermissions, "10000");
            return settings;
        }

        public override SPHealthCheckStatus Check()
        {
            if (!SPFarm.Joined)
            {
                throw new InvalidOperationException();
            }
            
            // setup
            results = "";
            StringBuilder sb = new StringBuilder();

            foreach (SPWebApplication webApplication in SPWebService.ContentService.WebApplications)
            {
                if (webApplication.Status == SPObjectStatus.Online)
                {
                    foreach (SPContentDatabase contentDatabase in webApplication.ContentDatabases)
                    {
                        foreach (SPSite site in contentDatabase.Sites)
                        {
                            try
                            {
                                long numUniquelySecuredItems = GetContentSecuredItems(contentDatabase, site.ID);
                                if (numUniquelySecuredItems > Convert.ToInt64(MaxUniquePermissions))
                                {
                                    sb.AppendLine(String.Format("{0} has {1} uniquely permissioned items. ", site.Url, numUniquelySecuredItems.ToString()));
                                }
                            }
                            catch { /*Best effort*/ }
                        }
                    }
                }
            }

            results = sb.ToString();
            if (!string.IsNullOrEmpty(results))
                return SPHealthCheckStatus.Failed;

            return SPHealthCheckStatus.Passed;
        }

        private static long GetContentSecuredItems(SPContentDatabase contentDatabase, Guid siteId)
        {

            int retval = 0;
            
            using (SqlConnection connection = new SqlConnection(contentDatabase.DatabaseConnectionString))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand { Connection = connection, CommandText = String.Format(GET_UNIQUE_PERMS_COUNT, siteId.ToString("d")) })
                {

                    object temp = command.ExecuteScalar();
                    if (temp != null)
                    {
                        try
                        {
                            return Convert.ToInt64(temp);
                        }
                        catch { /* Best effort */ }
                    }
                }
            }

            return retval;

        }
        #endregion
    
    }
}
